package com.ch.mobilesha.img;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.widget.ImageButton;
import android.widget.ImageSwitcher;
import android.widget.ImageView;

import com.ch.mobilesha.net.NetManager;

public class DrawableCacheManager {

	private static DrawableCacheManager instance;

	private Map<String, DrawableReference> map;// 用于Cache内容的存储
	private ReferenceQueue<UrlDrawable> queue;// 软引用Reference的队列

	private static final int IV_VIEW = 10;
	private static final int IS_VIEW = 11;
	private static final int IB_VIEW = 12;

	private ImageSwitcher is;
	private ImageView iv;
	private ImageButton ib;

	private ControlHandler handler;


	public static DrawableCacheManager getInstance(Context context) {
		if (instance == null)
			instance = new DrawableCacheManager(context);
		return instance;
	}

	private DrawableCacheManager(Context context) {
		map = new HashMap<String, DrawableReference>();// 用于Chche内容的存储
		queue = new ReferenceQueue<UrlDrawable>();// 垃圾Reference的队列
		handler = new ControlHandler(context.getMainLooper());
	}

	public void setImageSwitcherDrawable(ImageSwitcher view, String url) {
		Drawable drawable = getDrawable(url);
		if (drawable != null) {
			view.setImageDrawable(drawable);
		} else {
			this.is = view;
			new DownloadDrawableTask(url, IS_VIEW).start();
		}

	}

	public void setImageViewDrawable(ImageView view, String url) {
		Drawable drawable = getDrawable(url);
		if (drawable != null) {
			view.setImageDrawable(drawable);
		} else {
			this.iv = view;
			new DownloadDrawableTask(url, IV_VIEW).start();
		}
	}

	public void setImageViewDrawable(ImageButton view, String url) {
		Drawable drawable = getDrawable(url);
		if (drawable != null) {
			view.setImageDrawable(drawable);
		} else {
			this.ib = view;
			new DownloadDrawableTask(url, IB_VIEW).start();
		}
	}

	/**
	 * get the drawable
	 * 
	 * @param url
	 * @return
	 */
	public Drawable getDrawable(String url) {
		UrlDrawable ud = null;
		if (map.containsKey(url)) {
			DrawableReference reference = map.get(url);
			if (reference != null) {
				ud = reference.get();
			}
		}
		if (ud == null) {
			// 如果SDCARD可用:
			if (Environment.getExternalStorageState().equals(
					Environment.MEDIA_MOUNTED)) {
				String path = FileManager.getImgFolderPath() + "/" + url.hashCode();
				if (path != null && !"".equals(path)) {
					Drawable drawable = Drawable.createFromPath(path);
					if (drawable != null) {
						put(drawable, url);
						return drawable;
					}
				}
			}
			return null;
		} else
			return ud.getDrawable();
	}

	/**
	 * put the drawable of inputstream
	 * 
	 * @param in
	 * @param url
	 * @throws Exception
	 */
	public void put(InputStream in, String url) throws Exception {
		try {
			if (in != null && url != null && !"".equals(url)) {
				Drawable drawable = Drawable.createFromStream(in, null);
				put(drawable, url);
				// 如果SDCARD可用:
				if (Environment.getExternalStorageState().equals(
						Environment.MEDIA_MOUNTED)) {
					File file = new File(
							FileManager.getImgFolderPath() + "/"
									+ url.hashCode());
					if (file != null && !file.exists()) {
						if (!file.getParentFile().exists()) {
							file.getParentFile().mkdirs();
						}
						FileOutputStream fos = new FileOutputStream(file);
						byte[] buffer = new byte[1024];
						int len = -1;
						while ((len = in.read(buffer)) != -1) {
							fos.write(buffer, 0, len);
						}
						fos.flush();
						fos.close();
						in.close();
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception(e.getMessage(), e);
		}
	}

	/**
	 * put the drawable
	 * 
	 * @param drawable
	 * @param url
	 */
	public void put(Drawable drawable, String url) {
		cleanDrawableCache();
		UrlDrawable value = new UrlDrawable(url, drawable);
		DrawableReference dr = new DrawableReference(value, queue);
		map.put(dr.url, dr);
	}

	private void cleanDrawableCache() {
		DrawableReference reference = null;
		while ((reference = (DrawableReference) queue.poll()) != null) {
			map.remove(reference.url);
		}
	}

	/**
	 * clear all the cache
	 */
	public void clearCache() {
		cleanDrawableCache();
		map.clear();
		System.gc();
		return;
	}

	private final class ControlHandler extends Handler {

		public ControlHandler(Looper looper) {
			super(looper);
		}

		@Override
		public void dispatchMessage(Message msg) {
			switch (msg.what) {
			case 1:
				switch (msg.getData().getInt("viewid")) {
				case IV_VIEW:
					iv.setImageDrawable(getDrawable(msg.getData().getString(
							"url")));
					break;

				case IS_VIEW:
					is.setImageDrawable(getDrawable(msg.getData().getString(
							"url")));
					break;

				case IB_VIEW:
					ib.setImageDrawable(getDrawable(msg.getData().getString(
							"url")));
					break;
				}
				break;
			}
		}
	}

	private final class DownloadDrawableTask extends Thread {

		private String url;
		private int viewid;

		public DownloadDrawableTask(String url, int viewid) {
			this.url = url;
			this.viewid = viewid;
		}

		@Override
		public void run() {
			try {
				InputStream is = NetManager.handleGetRequest(url);
				if(is!=null){
					put(is, url);
					Message message = new Message();
					message.what = 1;
					message.getData().putString("url", url);
					message.getData().putInt("viewid", viewid);
					handler.sendMessage(message);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private final class DrawableReference extends SoftReference<UrlDrawable> {

		private String url;

		public DrawableReference(UrlDrawable r) {
			super(r);
			this.url = r.getUrl();
		}

		public DrawableReference(UrlDrawable r,
				ReferenceQueue<? super UrlDrawable> q) {
			super(r, q);
			this.url = r.getUrl();
		}
	}

	private class UrlDrawable {
		private String url;
		private Drawable drawable;

		public UrlDrawable(String url, Drawable drawable) {
			this.url = url;
			this.drawable = drawable;
		}

		public String getUrl() {
			return url;
		}

		public Drawable getDrawable() {
			return drawable;
		}
	}
}
